package com.nvwa.coding.util.fn;

import com.nvwa.coding.util.safe.Coding;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;


/**
 * 快速构建一些常用函数，用来支持链式编程
 */
public abstract class Fn {

    public static <T> Function<T, T> self() {
        return o -> o;
    }

    public static <T> Consumer<T> nonNullThen(Consumer<T> consumer) {
        return o -> {
            if (o != null) {
                consumer.accept(o);
            }
        };
    }

    public static <T> Predicate<T> nonNullAnd(Predicate<T> test) {
        return o -> o != null && test.test(o);
    }

    public static <T, R> Function<T, R> nonNullThen(Function<T, R> getter) {
        return o -> o == null ? null : getter.apply(o);
    }


    public static <T, C extends Collection<E>, E> Function<T, Stream<E>> stream(Function<T, C> getter) {
        return nonNullThen(getter).andThen(Coding::stream);
    }

    public static <T> Function<T, String> ensureStr(Function<T, String> getter) {
        return nonNullThen(getter).andThen(Coding::ensure);
    }

    public static <T> Function<T, Boolean> ensureBool(Function<T, Boolean> getter) {
        return nonNullThen(getter).andThen(Coding::ensure);
    }

    public static <T> Function<T, Byte> ensureByte(Function<T, Byte> getter) {
        return nonNullThen(getter).andThen(Coding::ensure);
    }

    public static <T> Function<T, Short> ensureShort(Function<T, Short> getter) {
        return nonNullThen(getter).andThen(Coding::ensure);
    }
    public static <T> Function<T, Integer> ensureInt(Function<T, Integer> getter) {
        return nonNullThen(getter).andThen(Coding::ensure);
    }

    public static <T> Function<T, Long> ensureLong(Function<T, Long> getter) {
        return nonNullThen(getter).andThen(Coding::ensure);
    }

    public static <T> Function<T, Float> ensureFloat(Function<T, Float> getter) {
        return nonNullThen(getter).andThen(Coding::ensure);
    }

    public static <T> Function<T, Double> ensureDouble(Function<T, Double> getter) {
        return nonNullThen(getter).andThen(Coding::ensure);
    }

    public static <T> Function<T, BigDecimal> ensureBigDecimal(Function<T, BigDecimal> getter) {
        return nonNullThen(getter).andThen(Coding::ensure);
    }

    public static <T, E> Function<T, List<E>> ensureList(Function<T, List<E>> getter) {
        return nonNullThen(getter).andThen(Coding::ensure);
    }

    public static <T, E> Function<T, Set<E>> ensureSet(Function<T, Set<E>> getter) {
        return nonNullThen(getter).andThen(Coding::ensure);
    }

    public static <T, K, V> Function<T, Map<K, V>> ensureMap(Function<T, Map<K, V>> getter) {
        return nonNullThen(getter).andThen(Coding::ensure);
    }


    public static <E, T extends Collection<E>> Consumer<T> mergeWith(Collection<? extends E> collection) {
        return origin -> {
            if (collection != null) {
                origin.addAll(collection);
            }
        };
    }

    public static <E, T extends Collection<E>> Consumer<T> add(E e) {
        return origin -> {
            if (e != null) {
                origin.add(e);
            }
        };
    }

    public static <K, V, T extends Map<K, V>> Consumer<T> mergeWith(Map<K, ? extends V> map) {
        return origin -> {
            if (map != null) {
                origin.putAll(map);
            }
        };
    }

    public static <K, V, T extends Map<K, V>> Consumer<T> put(K k, V v) {
        return origin -> {
            if (k != null) {
                origin.put(k, v);
            }
        };
    }


}
